/*
 * @Author: yehongbo 1394168736@qq.com
 * @Date: 2024-06-04 20:14:40
 * @LastEditors: yehongbo 1394168736@qq.com
 * @LastEditTime: 2024-09-21 16:00:39
 * @FilePath: \myWorkspace\react-basic\src\components\zuxian\parent.jsx
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
使用 Immer 编写简洁的更新逻辑

如果你的 state 有多层的嵌套，你或许应该考虑 将其扁平化。但是，如果你不想改变 state 的数据结构，你可能更喜欢用一种更便捷的方式来实现嵌套展开的效果。Immer 是一个非常流行的库，它可以让你使用简便但可以直接修改的语法编写代码，并会帮你处理好复制的过程。通过使用 Immer，你写出的代码看起来就像是你“打破了规则”而直接修改了对象：

updatePerson(draft => {
  draft.artwork.city = 'Lagos';
});

但是不同于一般的 mutation，它并不会覆盖之前的 state！

由 Immer 提供的 draft 是一种特殊类型的对象，被称为 Proxy，它会记录你用它所进行的操作。这就是你能够随心所欲地直接修改对象的原因所在！
从原理上说，Immer 会弄清楚 draft 对象的哪些部分被改变了，并会依照你的修改创建出一个全新的对象。

尝试使用 Immer:

    运行 npm install use-immer 添加 Immer 依赖
    用 import { useImmer } from 'use-immer' 替换掉 import { useState } from 'react'

*/

import { useState } from 'react';
import { useImmer } from 'use-immer'
const Form = () => {
    const [person, setPerson] = useState({
        firstName: 'Barbara',
        lastName: 'Hepworth',
        email: 'bhepworth@sculpture.com'
    });

    function handleChange(e) {
        console.log('e', e)
        setPerson({
            ...person,
            [e.target.name]: e.target.value
        });
    }



    return (
        <>
            <label>
                First name:
                <input
                    name="firstName"
                    value={person.firstName}
                    onChange={handleChange}
                />
            </label>
            <label>
                Last name:
                <input
                    name="lastName"
                    value={person.lastName}
                    onChange={handleChange}
                />
            </label>
            <label>
                Email:
                <input
                    name="email"
                    value={person.email}
                    onChange={handleChange}
                />
            </label>
            <p>
                {person.firstName}{' '}
                {person.lastName}{' '}
                ({person.email})
            </p>
        </>
    );
}
// 多层嵌套的对象使用immer写法更接近js
const form1 = () => {
    const [person, updatePerson] = useImmer({
        name: 'Niki de Saint Phalle',
        artwork: {
            title: 'Blue Nana',
            city: 'Hamburg',
            image: 'https://i.imgur.com/Sd1AgUOm.jpg',
        }
    });

    function handleNameChange(e) {
        updatePerson(draft => {
            draft.name = e.target.value;
        });
        // updateMyList(draft => {
        //     const artwork = draft.find(a =>
        //         a.id === id
        //     );
        //     artwork.seen = nextSeen;
        // });
        // updateMyTodos(draft => {
        //     const artwork = draft.find(a => a.id === artworkId);
        //     artwork.seen = nextSeen;
        // });
    }

    function handleTitleChange(e) {
        updatePerson(draft => {
            draft.artwork.title = e.target.value;
        });
    }

    function handleCityChange(e) {
        updatePerson(draft => {
            draft.artwork.city = e.target.value;
        });
    }

    function handleImageChange(e) {
        updatePerson(draft => {
            draft.artwork.image = e.target.value;
        });
    }

    // 使用数组的一个小缺点是，对于每个项目，你都需要调用 selectedIds.includes(letter.id) 来检查它是否被选中。如果数组非常大，则这可能会成为性能问题，因为带有 includes() 的数组搜索需要线性时间，并且你正在为每个单独的项目执行此搜索。

    //  要解决这个问题，你可以在 state 中使用一个 Set 对象，它提供了快速的 has() 操作
    const [selectedIds, setSelectedIds] = useState(
        new Set()
    );

    function handleToggle(toggledId) {
        // Create a copy (to avoid mutation).
        const nextIds = new Set(selectedIds);
        if (nextIds.has(toggledId)) {
            nextIds.delete(toggledId);
        } else {
            nextIds.add(toggledId);
        }
        setSelectedIds(nextIds);
    }

    return (
        <>
            <label>
                Name:
                <input
                    value={person.name}
                    onChange={handleNameChange}
                />
            </label>
            <label>
                Title:
                <input
                    value={person.artwork.title}
                    onChange={handleTitleChange}
                />
            </label>
            <label>
                City:
                <input
                    value={person.artwork.city}
                    onChange={handleCityChange}
                />
            </label>
            <label>
                Image:
                <input
                    value={person.artwork.image}
                    onChange={handleImageChange}
                />
            </label>
            <p>
                <i>{person.artwork.title}</i>
                {' by '}
                {person.name}
                <br />
                (located in {person.artwork.city})
            </p>
            <img
                src={person.artwork.image}
                alt={person.artwork.title}
            />
        </>
    );
}

const List = () => {
    const [name, setName] = useState('');
    const [artists, setArtists] = useState([]);
    let initialArtists = [
        { id: 0, name: 'Marta Colvin Andrade' },
        { id: 1, name: 'Lamidi Olonade Fakeye' },
        { id: 2, name: 'Louise Nevelson' },
    ];
    const [artists1, setArtists1] = useState(
        initialArtists
    );

    let initialShapes = [
        { id: 0, type: 'circle', x: 50, y: 100 },
        { id: 1, type: 'square', x: 150, y: 100 },
        { id: 2, type: 'circle', x: 250, y: 100 },
    ];
    const [shapes, setShapes] = useState(
        initialShapes
    );

    let initialCounters = [
        0, 0, 0
    ];
    const [counters, setCounters] = useState(
        initialCounters
    );
    function handleIncrementClick(index) {
        const nextCounters = counters.map((c, i) => {
            if (i === index) {
                // 递增被点击的计数器数值
                return c + 1;
            } else {
                // 其余部分不发生变化
                return c;
            }
        });
        setCounters(nextCounters);
    }

    return (
        <>
            <ul>
                {counters.map((counter, i) => (
                    <li key={i}>
                        {counter}
                        <button onClick={() => {
                            handleIncrementClick(i);
                        }}>+1</button>
                    </li>
                ))}
            </ul>
            <h1>振奋人心的雕塑家们：</h1>
            <input
                value={name}
                onChange={e => setName(e.target.value)}
            />
            <button onClick={() => {
                setArtists([
                    ...artists,
                    { id: nextId++, name: name }
                    // push
                ]);

                setArtists([
                    { id: nextId++, name: name },
                    ...artists,
                    // unshift
                ]);

                const insertAt = 1; // 可能是任何索引
                const nextArtists = [
                    // 插入点之前的元素：
                    ...artists.slice(0, insertAt),
                    // 新的元素：
                    { id: nextId++, name: name },
                    // 插入点之后的元素：
                    ...artists.slice(insertAt)
                ];
                setArtists(nextArtists);
                // 在中间插入数据

                const nextList = [...artists];
                nextList.reverse();
                nextList.sort()
                nextList[0].seen = true; // 问题：直接修改了 list[0] 的值
                // 虽然 nextList 和 list 是两个不同的数组，nextList[0] 和 list[0] 却指向了同一个对象。因此，
                // 通过改变 nextList[0].seen，list[0].seen 的值也被改变了。这是一种 state 的 mutation 操作，你应该避免这么做！
                // 你可以用类似于 更新嵌套的 JavaScript 对象 的方式解决这个问题——拷贝想要修改的特定元素，而不是直接修改它。
                setArtists(nextList);
                // 其他修改数组的方式

                setArtists1(
                    artists1.filter(a =>
                        a.id !== artist1.id
                    )
                    // 过滤的写法就是生成新数组进行操作  删除操作
                );
                setShapes(
                    shapes.map(shape => {
                        if (shape.type === 'square') {
                            // 不作改变
                            return shape;
                        } else {
                            // 返回一个新的圆形，位置在下方 50px 处
                            return {
                                ...shape,
                                y: shape.y + 50,
                            };
                        }
                    })
                )

            }}>添加</button>
            <ul>
                {artists.map(artist => (
                    <li key={artist.id}>{artist.name}</li>
                ))}
            </ul>
        </>
    );
}
